package fr.lip6.meta.ple.featureIdentification;

import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

import fr.lip6.meta.tools.Trigger;

import artefact.generic.Artefact;

public class SiFeatureExtraction {

	
	public Collection<Feature> features = null;
	public Collection<Product> getAllP() {
		return AllP;
	}

	public void setAllP(Collection<Product> allP) {
		AllP = allP;
	}

	private Collection<Product> AllP = null;
	
	// A ameliorer
	public Collection<Feature> extract(Collection<Artefact> artefacts) {
		AllP = new ArrayList<Product>();
		Collection<Product> AllP_cp = new ArrayList<Product>();
		//int id = 1;
		
		for (Artefact a : artefacts) {
			int idd = a.getId();
			Product p = new Product(ArtefactToTriggers.extract(a), idd);
			// A ameliorer 
			p.removeRepeated();
			AllP.add(p);
			AllP_cp.add((Product)p.clone());
		}
		
		features = featureIdentification(AllP_cp);
		
		return features;
	}
	
	/**
	 * Prints in a file the features information
	 * @param fileName - the name of the destination file
	 * @throws NullRootException
	 * @throws IOException
	 */
	public void featuresToFile(String fileName) throws NullRootException,
			IOException {
		if (features == null) throw new NullRootException();
		
        FileWriter fw = new FileWriter(fileName);;
        PrintWriter pw = new PrintWriter(fw);
        int pSize = AllP.size();
        
        identifyFeatures(features);
        
        //Printing information
		pw.println("PRODUCTS - FEATURES:");
        for (Product prod : AllP)
        	pw.println(prod.getId() + ": " +
        			prod.featuresImplementedString(features));
        pw.println("\n\nPRODUCTS: " + pSize + "\n");
        for (Product prod : AllP)
        	pw.println(prod);
        pw.println("\n\nFEATURES: " + features.size() + "\n");
        for (Feature f : features) {
        	Collection<Integer> p = f.getProdIds();
        	int rate = (p.size() * 100) / pSize;
        	pw.println(f.getId() + " [rate " + rate + "%]: " + p);
        	pw.println(f.toStringLines(1));
        }
        fw.close();
	}

	//@SuppressWarnings("unchecked")
	private Collection<Feature> featureIdentification(Collection<Product> AllP) {
		ArrayList<Feature> features = new ArrayList<Feature>();
		ConstructionPrimitiveSortedList cps =
			new ConstructionPrimitiveSortedList(AllP);
		
		while (!cps.isEmpty()) {
			//Le trigger soit le truc transition present dans le plus de produit
			ConstructionPrimitiveInfo selected_cp = cps.getMostFrequentCp();
			// recuperation liste des produits
			List<Product> selected_products = selected_cp.getProdList();
			// on sais que le feature est present dans pas mal de produit, on chercher donc lintersection entre ces produits
			Feature f = Feature.extractIntersection(selected_products);
			
			cps.removeAllTriggers(f);
			features.add(f);
		}
		
		return features;
	}

	/**
	 * Sets an id for each feature
	 * @param features
	 */
	private void identifyFeatures(Collection<Feature> features) {
		int id = 0;
		for (Feature f : features) {
			f.setId("F" + id++);
		}
	}
}

//je pense que cest ou l'on peut voir ou les 
//features sont le plus present des nos produits
class ConstructionPrimitiveSortedList extends
		ArrayList<ConstructionPrimitiveInfo> {

	private static final long serialVersionUID = 611L;
	
	public ConstructionPrimitiveSortedList(Collection<Product> ct) {
		for (Product p : ct) {
			for (Trigger t : p)
				addTrigger(t, p);
		}
		Collections.sort(this);
	}
	
	public void removeAllTriggers(Collection<Trigger> ct) {
		for (Trigger t : ct) {
			removeTrigger(t);
		}
		Collections.sort(this);
	}
	
	public ConstructionPrimitiveInfo getMostFrequentCp() {
		return get(0);
	}
	
	private void addTrigger(Trigger t, Product prod) {
		ConstructionPrimitiveInfo cp = containingTrigger(t);
		if (cp == null) {
			cp = new ConstructionPrimitiveInfo(t, prod);
			// bizarre ?
			add(cp);
			//
		}
		else 
			cp.addProduct(prod);
	}
	
	private void removeTrigger(Trigger t) {
		ConstructionPrimitiveInfo cp = containingTrigger(t);
		if (cp != null)
			remove(cp);
	}
	
	private ConstructionPrimitiveInfo containingTrigger(Trigger t) {
		for (ConstructionPrimitiveInfo cp : this) {
			if (cp.isSameTrigger(t)) return cp;
		}
		return null;
	}
}


class ConstructionPrimitiveInfo implements
		Comparable<ConstructionPrimitiveInfo> {
	
	private Trigger cp;
	private ArrayList<Product> prodList = new ArrayList<Product>();

	public ConstructionPrimitiveInfo(Trigger cp, Product prod) {
		this.cp = cp;
		prodList.add(prod);
	}
	
	@Override
	public int compareTo(ConstructionPrimitiveInfo other) {
		int freq_this = prodList.size();
		int freq_other = other.prodList.size();
		if (freq_this < freq_other) return 1;
		if (freq_this > freq_other) return -1;
		return 0;
	}
	
	public void addProduct(Product prod) {
		if (!prodList.contains(prod))
			prodList.add(prod);
	}
	
	public boolean isSameTrigger(Trigger t) {
		return t.equals(cp);
	}

	public Trigger getCp() {
		return cp;
	}

	public ArrayList<Product> getProdList() {
		return prodList;
	}
}

